
class AsyncTransportHandler:
    def on_connected(self):
        raise NotImplementedError()
    def on_read(self, event):
        raise NotImplementedError()
    def on_writed(self, event):
        raise NotImplementedError()
    def on_error(self, errno):
        raise NotImplementedError()
    def on_disconnected(self, active):
        raise NotImplementedError()

    def __str__(self):
        return "AsyncTransportHandler"


from transport import Transport
from error import InactiveCloseError, ConnectionStateError, Errno




import logging
log = logging


from connector import ConnectorWithArgs
from event import Event, SimpleHandler
from event_creator import EventCreator
from queue import Queue
class AsyncTransportWrapper(Transport):
    #default: 1. on_connected->register readable event; 
    #         2. on_read ->register writable event
    class DefaultHandler(AsyncTransportHandler):
        def __init__(self, wrapper):
            self.__wrapper = wrapper

        def wrapper(self):
            return self.__wrapper
        def transport(self):
            return self.__wrapper.transport()
        def reactor(self):
            return self.__wrapper.reactor()

        def on_connected(self):
            print("Connected Transport:{}".format(self.transport()))
            self.wrapper().register_recv() # register the readable event

        def on_read(self, event):
            try:
                #TODO: get all bytes write it into recv queue
                read_bytes = self.transport().recv(4096)
                print(f"Read data:{read_bytes}") 
                if len(read_bytes) > 0:
                    self.wrapper().recv_queue().put(read_bytes)
                    print("read data -> enqueue, Queue-len:{}".format(self.wrapper().recv_queue().qsize()))

            except InactiveCloseError :
                self.on_error(Errno.INACTIVE_CLOSE) 
                self.on_disconnected(False)
                self.reactor().unregister(event.id())
            except ConnectionStateError:
                self.on_error(Errno.CONNECTION_LOST_UNEXPECTED)
                self.reactor().unregister(event.id())
            else:
                pass
                #self.wrapper().register_send() #register the writable event & data 


        def on_writed(self, event):
            try:
                #TODO for each data in send_queu, send it  and change the index
                byte_len = self.transport().send(b"hello world") 
                print(f"write data len:{byte_len}")
                if byte_len == 0: #write agian if buffer is full
                    self.wrapper().register_send()

            except ConnectionStateError:
                self.on_error(Errno.CONNECTION_LOST_UNEXPECTED)
                self.reactor().unregister(event.id())
            else:
                pass

        def on_error(self, errno):
            print(f"Error: got an error, errno:{errno}")

        def on_disconnected(self, active):
            print("Disconnected state:{}(True-Active|False-Inactive), transport:{},".format(active, self.transport()))

    def __init__(self, reactor, transport=None, handler=None):
        self.__reactor = reactor
        self.__transport = transport if transport is not None else Transport.from_tcp()
        self.__handler = AsyncTransportWrapper.DefaultHandler(self) if handler is None else handler
        self.__connector = None

        self.__send_queue = Queue()
        self.__recv_queue = Queue()


    def reactor(self):
        return self.__reactor
    def transport(self):
        return self.__transport
    def recv_queue(self):
        return self.__recv_queue
    def send_queue(self):
        return self.__send_queue

    def connect(self):
        self.__connector = ConnectorWithArgs(self.__transport, self.__reactor, self.__handler.on_connected).connect()


    def send(self, byte_buffer):
        if len(byte_buffer) > 0:
            ret = self.__send_queue.put(byte_buffer) 
            self.register_send()
            return ret
        return 0

    def recv(self, buf_size=1):
        if not self.__recv_queue.empty():
            return self.__recv_queue.get_nowait()
        return None

    def register_send(self):
        if self.is_connected():
            ev = EventCreator.from_writable(self.__transport.handle(), SimpleHandler.Writable(self.__handler.on_writed), False)
            self.__reactor.register(ev)
        else:
            pass

    def register_recv(self):
        if self.is_connected():
            ev = EventCreator.from_readable(self.__transport.handle(), SimpleHandler.Readable(self.__handler.on_read), True)
            self.__reactor.register(ev)
        else:
            pass

    def disconnect(self):
        if self.is_connected():
            self.__transport.disconnect()
            self.__handler.on_disconnected(True)
        else:
            pass

    def is_connected(self):
        return self.__transport.is_connected()

    def close(self):
        self.__transport.close()

    def handle(self):
        return self.__transport.handle()




import unittest
from reactor import Reactor
class TestAsyncTransport(unittest.TestCase):
    def test_main(self):
        trans = Transport.from_tcp()
        trans = AsyncTransportWrapper(Reactor(), trans)
        trans.connect()

        thread = trans.reactor().loop_in_thread() #TODO: in thread

        
        s = None
        import time
        for i in range(10):
            time.sleep(0.500)
            s = trans.recv()
            while  s is not None:
                print("recv data from transport:{}".format(s))
                s = trans.recv()


        trans.reactor().loop_exit()

        trans.disconnect()

        trans.close()

        thread.join()




if __name__ == "__main__":
    unittest.main(verbosity=2)
